#include <cmath>
#include <QtOpenGL>
#include "camera.h"

Camera::Camera(const float angleX, const float angleY, const float distance)
: lookFrom(3, 0)
, angleX(angleX)
, angleY(angleY)
, distance(distance)
{
}

void Camera::look()
{
	glMatrixMode(GL_MODELVIEW);	
	glLoadIdentity();
	calcLookFrom();
	gluLookAt(lookFrom[0], lookFrom[1], lookFrom[2],
		0, 0, 0,
		0.0, 1.0, 0.0);
}

std::vector<float> Camera::getPosition()
{
	calcLookFrom();
	return lookFrom;
}

void Camera::rotateX( const float dX)
{
	float aX = asin(sin(angleX - dX));

	if (aX > -0.1)
		aX = -0.1;
	if (aX < -M_PI/2 + 0.1)
		aX = -M_PI/2 + 0.1;

	if (aX != angleX)
		angleX = aX;
}

void Camera::rotateY( const float dY)
{
	float aY = angleY - dY;

	while(aY > 2 * M_PI)
		aY -= 2 * M_PI;

	while(aY < 0)
		aY += 2 * M_PI;

    if (aY != angleY)
		angleY = aY;
}

void Camera::addDistance(const float delta)
{
	distance += delta;

	if (distance < 26.5f)
		distance = 26.5f;
	if (distance > 60.0f)
		distance = 60.0f;
}

std::vector<float> Camera::getInverse() const
{
	float m[16] = {0};
	glGetFloatv(GL_MODELVIEW_MATRIX, m);

	std::vector<float> inverse(16, 0);

	inverse[0] = m[0]; inverse[1] = m[4]; inverse[2] = m[8];
	inverse[4] = m[1]; inverse[5] = m[5]; inverse[6] = m[9];
	inverse[8] = m[2]; inverse[9] = m[6]; inverse[10] = m[10];
	inverse[3] = 0.0f; inverse[7] = 0.0f; inverse[11] = 0.0f;
	inverse[15] = 1.0f;
	inverse[12] = -(m[12] * m[0]) - (m[13] * m[1]) - (m[14] * m[2]);
	inverse[13] = -(m[12] * m[4]) - (m[13] * m[5]) - (m[14] * m[6]);
	inverse[14] = -(m[12] * m[8]) - (m[13] * m[9]) - (m[14] * m[10]);

	return inverse;
}

void Camera::calcLookFrom()
{
	lookFrom[0] = distance * cos(angleX) * sin(angleY);
	lookFrom[1] = -distance * sin(angleX);
	lookFrom[2] = distance * cos(angleX) * cos(angleY);
}